
#ifndef __MAKE_CBEVENT_PARAM_ROUTINES_DEFINED__
#define __MAKE_CBEVENT_PARAM_ROUTINES_DEFINED__
#include <elastos.h>
#include <elapi.h>
#include <critsec.h>
#include <clsdef.h>
#include <elacfg.h>
#include <elatypes.h>

_ELASTOS_NAMESPACE_USING
//
// GetXxxCBEParamExtraSize
//

MemorySize _Impl_GetCarArrayCBEParamExtraSize(MemorySize typeSize, PCarQuintet param)
{
    return ROUNDUP2(sizeof(CarQuintet) + (param? param->m_size : 0), 4);
}


MemorySize _Impl_GetAStringCBEParamExtraSize(MemorySize typeSize, AString param)
{
    Int32 len = param? strlen(param) : 0;
    if (len) return ROUNDUP2((len + 1) * sizeof(AChar), 4);
    return 4;
}

MemorySize _Impl_GetWStringCBEParamExtraSize(MemorySize typeSize, WString param)
{
    Int32 len = param? wcslen(param) : 0;
    if (len) return ROUNDUP2((len + 1) * sizeof(WChar), 4);
    return 4;
}

MemorySize _Impl_GetArrayOfAStringCBEParamExtraSize(MemorySize typeSize, ArrayOf<AString> & param)
{
    int used = param.GetLength();
    MemorySize len = 0;

    len = _Impl_GetCarArrayCBEParamExtraSize(typeSize, param);

    for (int i = 0; i < used; ++i) {
        if(!param[i].IsNull())
            len += ROUNDUP2((strlen(param[i]) + 1) * sizeof(AChar), 4);
    }
    return len;
}

MemorySize _Impl_GetArrayOfWStringCBEParamExtraSize(MemorySize typeSize, ArrayOf<WString> & param)
{
    int used = param.GetLength();
    MemorySize len = 0;

    len = _Impl_GetCarArrayCBEParamExtraSize(typeSize, param);

    for (int i = 0; i < used; ++i) {
        if(!param[i].IsNull())
            len += ROUNDUP2((wcslen(param[i]) + 1) * sizeof(WChar), 4);
    }
    return len;
}

MemorySize _Impl_GetBufferOfAStringCBEParamExtraSize(MemorySize typeSize, BufferOf<AString> & param)
{
    int used = param.GetUsed();
    MemorySize len = 0;

    len = _Impl_GetCarArrayCBEParamExtraSize(typeSize, param);

    for (int i = 0; i < used; ++i) {
        if(!param[i].IsNull())
            len += ROUNDUP2((strlen(param[i]) + 1) * sizeof(AChar), 4);
    }
    return len;
}

MemorySize _Impl_GetBufferOfWStringCBEParamExtraSize(MemorySize typeSize, BufferOf<WString> & param)
{
    int used = param.GetUsed();
    MemorySize len = 0;

    len = _Impl_GetCarArrayCBEParamExtraSize(typeSize, param);

    for (int i = 0; i < used; ++i) {
        if(!param[i].IsNull())
            len += ROUNDUP2((wcslen(param[i]) + 1) * sizeof(WChar), 4);
    }
    return len;
}

//
// MakeXxxCBEventParam
//

void _Impl_MakeEMuidCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    assert(extraSize == sizeof(EMuid));
    EMuid **ppEGuid = (EMuid**)ppParam;

    memcpy(*ppBuf, *ppEGuid, sizeof(EMuid));
    (*ppEGuid) = (EMuid *)(*ppBuf);
    (*ppBuf) += sizeof(EMuid);
}

void _Impl_MakeEGuidCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    assert(extraSize == sizeof(EGuid));
    EGuid **ppEGuid = (EGuid**)ppParam;

    memcpy(*ppBuf, *ppEGuid, sizeof(EGuid));
    (*ppEGuid) = (EGuid *)(*ppBuf);
    (*ppBuf) += sizeof(EGuid);
}


void _Impl_MakeCarArrayCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    assert(extraSize == (MemorySize)ROUNDUP2(sizeof(CarQuintet) + ((PCarQuintet)*ppParam)->m_size, 4));

    *(PCarQuintet)*ppBuf = *(PCarQuintet)*ppParam;
    ((PCarQuintet)*ppBuf)->m_pBuf = (PVoid)(((PCarQuintet)*ppBuf) + 1);
    memcpy(((PCarQuintet)*ppBuf)->m_pBuf, ((PCarQuintet)*ppParam)->m_pBuf, ((PCarQuintet)*ppParam)->m_size);
    *ppParam = *(PCarQuintet *)ppBuf;
    (*ppBuf) += extraSize;
}

void _Impl_MakeArrayOfAStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    ArrayOf<AString> *pParam = (ArrayOf<AString>*)*ppParam;
    int used = pParam->GetLength();
    int len = 0;
    char * pBuf;

    *(PCarQuintet)*ppBuf = *(PCarQuintet)pParam;
    ((PCarQuintet)*ppBuf)->m_pBuf = (PVoid)(((PCarQuintet)*ppBuf) + 1);
    memcpy(((PCarQuintet)*ppBuf)->m_pBuf, ((PCarQuintet)pParam)->m_pBuf, ((PCarQuintet)pParam)->m_size);

    pBuf = (char*)((Byte*)((PCarQuintet)*ppBuf)->m_pBuf + ((PCarQuintet)pParam)->m_size);
    len = 0;
    for(int i=0; i<used; ++i) {
        pBuf = pBuf + len;
       (*(ArrayOf<AString>*)*ppBuf)[i] = (const char *)pBuf;
        len = 0;
        if ((*pParam)[i]) {
            len = (strlen((*pParam)[i])+1)*sizeof(AChar);
            if (len == 1) (*(ArrayOf<AString>*)*ppBuf)[i] = '\0';
            else memcpy( (void*)(const char*)(*(ArrayOf<AString>*)*ppBuf)[i], (*pParam)[i], len);
            len = ROUNDUP2(len, 4);
        }
        else (*(ArrayOf<AString>*)*ppBuf)[i] = NULL;
    }
    *ppParam = (PCarQuintet)*ppBuf;
    (*ppBuf) += extraSize;
}

void _Impl_MakeArrayOfWStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    ArrayOf<WString> *pParam = (ArrayOf<WString>*)*ppParam;
    int used = pParam->GetLength();
    int len = 0;
    Byte * pBuf;

    *(PCarQuintet)*ppBuf = *(PCarQuintet)pParam;
    ((PCarQuintet)*ppBuf)->m_pBuf = (PVoid)(((PCarQuintet)*ppBuf) + 1);
    memcpy(((PCarQuintet)*ppBuf)->m_pBuf, ((PCarQuintet)pParam)->m_pBuf, ((PCarQuintet)pParam)->m_size);

    pBuf =  (Byte *)(wchar_t*)((Byte*)((PCarQuintet)*ppBuf)->m_pBuf + ((PCarQuintet)pParam)->m_size);
    len = 0;
    for(int i=0; i<used; ++i) {
        pBuf += len;
        (*(ArrayOf<WString>*)*ppBuf)[i] = (const wchar_t*)pBuf;
        len = 0;
        if ((*pParam)[i]) {
            len = (wcslen((*pParam)[i])+1)*sizeof(WChar);
            if (len == 2) (*(ArrayOf<WString>*)*ppBuf)[i] = L'\0';
            else memcpy( (void*)(const wchar_t*)(*(ArrayOf<WString>*)*ppBuf)[i], (*pParam)[i], len);
            len = ROUNDUP2(len, 4);
        }
        else (*(ArrayOf<WString>*)*ppBuf)[i] = NULL;
    }
    *ppParam = (PCarQuintet)*ppBuf;
    (*ppBuf) += extraSize;
}

void _Impl_MakeBufferOfAStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    BufferOf<AString> *pParam = (BufferOf<AString>*)*ppParam;
    int used = pParam->GetUsed();
    int len = 0;
    char * pBuf;

    *(PCarQuintet)*ppBuf = *(PCarQuintet)pParam;
    if (!pParam->IsNull()) {
        ((PCarQuintet)*ppBuf)->m_pBuf = (PVoid)(((PCarQuintet)*ppBuf) + 1);
        memcpy(((PCarQuintet)*ppBuf)->m_pBuf, ((PCarQuintet)pParam)->m_pBuf, ((PCarQuintet)pParam)->m_size);

        pBuf = (char*)((Byte*)((PCarQuintet)*ppBuf)->m_pBuf + ((PCarQuintet)pParam)->m_size);
        //(*(BufferOf<AString>*)*ppBuf)[0] = (const char *)pBuf;
        len = 0;
        for(int i=0; i<used; ++i) {
            pBuf = pBuf + len;
           (*(BufferOf<AString>*)*ppBuf)[i] = (const char *)pBuf;
            len = 0;
            if ((*pParam)[i]) {
                len = (strlen((*pParam)[i])+1)*sizeof(AChar);
                memcpy( (void*)(const char*)(*(BufferOf<AString>*)*ppBuf)[i], (*pParam)[i], len);
                len = ROUNDUP2(len, 4);
            }
            else (*(BufferOf<AString>*)*ppBuf)[i] = NULL;
        }
    }
    *ppParam = (PCarQuintet)*ppBuf;
    (*ppBuf) += extraSize;
}

void _Impl_MakeBufferOfWStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    BufferOf<WString> *pParam = (BufferOf<WString>*)*ppParam;
    int used = pParam->GetUsed();
    int len = 0;
    Byte * pBuf;

    *(PCarQuintet)*ppBuf = *(PCarQuintet)pParam;
    if (!pParam->IsNull()) {
        ((PCarQuintet)*ppBuf)->m_pBuf = (PVoid)(((PCarQuintet)*ppBuf) + 1);
        memcpy(((PCarQuintet)*ppBuf)->m_pBuf, ((PCarQuintet)pParam)->m_pBuf, ((PCarQuintet)pParam)->m_size);

        pBuf =  (Byte *)(wchar_t*)((Byte*)((PCarQuintet)*ppBuf)->m_pBuf + ((PCarQuintet)pParam)->m_size);
        //(*(BufferOf<WString>*)*ppBuf)[0] = (const wchar_t*)pBuf;
        len = 0;
        for(int i=0; i<used; ++i) {
            pBuf += len;
            (*(BufferOf<WString>*)*ppBuf)[i] = (const wchar_t*)pBuf;
            len = 0;
            if ((*pParam)[i]) {
                len = (wcslen((*pParam)[i])+1)*sizeof(WChar);
                memcpy( (void*)(const wchar_t*)(*(BufferOf<WString>*)*ppBuf)[i], (*pParam)[i], len);
                len = ROUNDUP2(len, 4);
            }
            else (*(BufferOf<WString>*)*ppBuf)[i] = NULL;
        }
    }
    *ppParam = (PCarQuintet)*ppBuf;
    (*ppBuf) += extraSize;
}


void _Impl_MakeAStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    AString *pParam = (AString *)*ppParam;
    if (pParam->IsNull() || pParam->IsEmpty()) {
        ((char*)(*ppBuf))[0] = '\0';
    }
    else memcpy(*ppBuf, (*pParam), extraSize);

    (*pParam) = (const char*)(*ppBuf);
    (*ppBuf) += ROUNDUP2(extraSize, 4);
}

void _Impl_MakeWStringCBEventParam(
        MemorySize extraSize, Byte **ppBuf, PVoid *ppParam)
{
    WString *pParam = (WString *)*ppParam;
    if (pParam->IsNull() || pParam->IsEmpty()) {
        ((wchar_t*)(*ppBuf))[0] = L'\0';
    }
    else memcpy(*ppBuf, (*pParam), extraSize);

    (*pParam) = (const wchar_t*)(*ppBuf);
    (*ppBuf) += ROUNDUP2(extraSize, 4);
}

ECode _Impl_CheckClsId(
        PInterface pServerObj,
        const ClassID* pClassiD,
        PInterface *ppServerObj)
{
    pServerObj = pServerObj->Probe(EIID_IInterface);
    assert(pServerObj);
    ClassID* pClsid = (ClassID*)pServerObj->Probe(EIID_CLASS_INFO);
    assert(pClsid);
    while (*(EMuid *)pClsid != *(EMuid *)pClassiD) {
        pServerObj = pServerObj->Probe(EIID_SUPER_OBJECT);
        if (NULL == pServerObj) return E_INVALID_ARGUMENT;

        pClsid = (ClassID*)pServerObj->Probe(EIID_CLASS_INFO);
    }
    *ppServerObj = pServerObj;  // don't AddRef, Caller don't Release either.
    return NOERROR;
}

ECode _Impl_AcquireCallbackHandler(
        PInterface pServerObj,
        REIID iid,
        PInterface *ppHandler)
{
    ICallbackSink *pSink = NULL;
    PInterface pHandler = NULL;
    ECode ec;

    do {
        if (pServerObj) {
            ec = _CObject_AcquireCallbackSink(pServerObj, &pSink);
            if (FAILED(ec)) return ec;
            pHandler = pSink->Probe(iid);
            if (pHandler) break;
        }
        else {
            return E_NO_INTERFACE;
        }

        pServerObj = pServerObj->Probe(EIID_SUPER_OBJECT);
        pSink->Release();

    } while (NULL == pHandler);

    *ppHandler = pHandler;
    return NOERROR;
}

#endif //__MAKE_CBEVENT_PARAM_ROUTINES_DEFINED__


